package filter

import (
	"context"
	"fmt"
	"github.com/SkyAPM/go2sky"
	"github.com/SkyAPM/go2sky/propagation"
	"github.com/SkyAPM/go2sky/reporter"
	"github.com/hyperway/pkg/component"
	"github.com/hyperway/pkg/config"
	"github.com/hyperway/pkg/logger"
)

type Go2SkyLifecycle int

var (
	SkyTracer *go2sky.Tracer
)

func NewGo2SkyLifecycle() *Go2SkyLifecycle {
	return new(Go2SkyLifecycle)
}

func (t *Go2SkyLifecycle) Title() string {
	return "go2sky"
}

func (t *Go2SkyLifecycle) OnPrepare() error {
	conf := config.GetWrapper("go2sky")
	enable := conf.GetBool("enable")
	if !enable {
		logger.Infow("go2sky未启用", "enable", enable)
		return nil
	}
	address := conf.GetString("address")
	r, err := reporter.NewGRPCReporter(address, reporter.WithLog(logger.GetLogger()))
	if err != nil {
		logger.Errorw("go2sky初始化失败", "error", err)
	}
	tracer, err := go2sky.NewTracer("hyperway", go2sky.WithReporter(r))
	SkyTracer = tracer
	if err != nil {
		logger.Errorw("[创建skywalking的tracer失败] maxwell:skywalking:tracer:create", "error", err)
	}
	return nil
}

// NewGo2SkyFilter creates a new Go2SkyFilter.
func NewGo2SkyFilter() component.PreRequestFilterFunc {

	conf := config.GetWrapper("go2sky")
	enable := conf.GetBool("enable")
	if !enable {
		logger.Infow("go2sky未启用", "enable", enable)
		return nil
	}

	return func(next component.RequestHandlerFunc) component.RequestHandlerFunc {
		return func(ctx component.WebContext) error {
			if ctx.URL().Path == "/hc.do" {
				return next(ctx)
			}
			span, traceCtx, err := SkyTracer.CreateEntrySpan(ctx.Context(), ctx.URL().String(), func(headerKey string) (string, error) {

				traceId := ctx.RequestId()
				spanCtx := &propagation.SpanContext{
					TraceID:         traceId,
					ParentSegmentID: traceId,
					Sample:          1,
				}
				ctx.SetVariable("TID", traceId)

				if headerKey == propagation.Header {
					return spanCtx.EncodeSW8(), nil
				}
				if headerKey == propagation.HeaderCorrelation {
					return spanCtx.EncodeSW8Correlation(), nil
				}
				return "", nil
			})

			if err != nil {
				return next(ctx)
			}

			defer func() {
				if span != nil {
					span.End()
				}
			}()
			span.SetComponent(2)
			span.SetSpanLayer(3)
			span.Tag(go2sky.TagHTTPMethod, ctx.Method())
			span.Tag(go2sky.TagURL, fmt.Sprintf("%s%s", ctx.Host(), ctx.URL().Path))
			ctx.SetContext(traceCtx)
			return next(ctx)
		}
	}
}

func (t *Go2SkyLifecycle) OnDestroy(ctx context.Context) error {
	return nil
}
